//
//  UIViewController+Tracking.m
//  test
//
//  Created by yun on 2018/4/8.
//  Copyright © 2018年 yun. All rights reserved.
//

#import "UIViewController+Tracking.h"
#import <objc/runtime.h>
@implementation UIViewController (Tracking)
/*
 +load 方法是在类被加载的时候调用的，而 +initialize 方法是在类或它的子类收到第一条消息之前被调用的，这里所指的消息包括实例方法和类方法的调用。也就是说 +initialize 方法是以懒加载的方式被调用的，如果程序一直没有给某个类或它的子类发送消息，那么这个类的 +initialize 方法是永远不会被调用的。此外 +load 方法还有一个非常重要的特性，那就是子类、父类和分类中的 +load 方法的实现是被区别对待的。换句话说在 Objective-C runtime 自动调用 +load 方法时，分类中的 +load 方法并不会对主类中的 +load 方法造成覆盖。综上所述，+load 方法是实现 Method Swizzling 逻辑的最佳“场所”。
 */

/*
 IMP block形式使用

 id b = [NSClassFromString(@"TestObj") new];
 SEL pushdata = NSSelectorFromString(@"setPushNewsData:");
 
 IMP aIMP = [b methodForSelector:pushdata];
 void (*setter)(id, SEL, NSString*) = (void(*)(id, SEL, NSString*))aIMP;
 
 setter(b, pushdata,@"");
 */
+ (void)load{
    // 防止手动调用，执行多次 原子操作
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class aClass = [self class];
        
        SEL originSel = @selector(viewWillAppear:);
        SEL swizzledSel = @selector(sw_viewWillAppear:);
        
        Method originM = class_getInstanceMethod(aClass, originSel);
        Method swizzledM = class_getInstanceMethod(aClass, swizzledSel);
        /*
         我们使用 Method Swizzling 的目的通常都是为了给程序增加功能，而不是完全地替换某个功能，所以我们一般都需要在自定义的实现中调用原始的实现。所以这里就会有两种情况需要我们分别进行处理：
         1、主类本身有实现需要替换的方法，也就是 class_addMethod 方法返回 NO 。这种情况的处理比较简单，直接交换两个方法的实现就可以了：
         2、主类本身没有实现需要替换的方法，而是继承了父类的实现，即 class_addMethod 方法返回 YES 。这时使用 class_getInstanceMethod 函数获取到的 originalSelector 指向的就是父类的方法，我们再通过执行 class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
         */
        BOOL success = class_addMethod(aClass, originSel, method_getImplementation(swizzledM), method_getTypeEncoding(swizzledM));
        if (success) {
            class_replaceMethod(aClass, swizzledSel, method_getImplementation(originM), method_getTypeEncoding(originM));
        } else {
            method_exchangeImplementations(originM, swizzledM);
        }
        
    });
}

/*
 ViewController调用viewWillAppear:方法时会调用自定义的sw_viewWillAppear：（因为方法交换了），sw_viewWillAppear：里调用sw_viewWillAppear:会调用系统viewWillAppear:（因为方法交换了），在自定义的方法里实现一些其他操作
 */
- (void)sw_viewWillAppear:(BOOL)animated{
    // 其他操作
    
    [self sw_viewWillAppear:animated];
    
}

@end
